package com.example.demo.service.comm;

import org.bson.Document;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class AggregationUtil {


    /**
     * //addFields
     *
     * @param strings 字段集合
     * @return AggregationOperation
     */
    public static AggregationOperation addFieldsToId(String... strings) {
        return var -> {
            Document documentStr = new Document ();
            Document document = new Document ( "$addFields", documentStr );
            for (String str : strings) {
                documentStr.append ( str, new Document ( "$toObjectId", "$" + str ) );
            }
            return document;
        };
    }

    /**
     * //addFieldsToStr
     *
     * @param strings 字段集合
     * @return AggregationOperation
     */
    public static AggregationOperation addFieldsToStr(String... strings) {
        return var -> {
            Document documentStr = new Document ();
            Document document = new Document ( "$addFields", documentStr );
            for (String str : strings) {
                documentStr.append ( str, new Document ( "$toString", "$" + str ) );
            }
            return document;
        };
    }

    /**
     * 获取外键的聚合语句
     *
     * @param criteria  条件
     * @param page      分页参数
     * @param pageSize  分页参数
     * @param strings   外键
     * @param collNames 外键的表
     * @param pro       需要返回的字段
     * @return Aggregation
     */
    public static Aggregation lookup(Criteria criteria, Integer page, Integer pageSize,
                                     String[] strings, String[] collNames, AggregationOperation... pro) {
        List<AggregationOperation> lists = new ArrayList<> ();
        SkipOperation skip = Aggregation.skip ( Long.parseLong ( String.valueOf ( (page - 1) * pageSize ) ) );
        LimitOperation limit = Aggregation.limit ( pageSize );
        //条件
        MatchOperation match = Aggregation.match ( criteria );
        //外键
        AggregationOperation addFieldsToId = addFieldsToId ( strings );
        lists.add ( match );
        lists.add ( addFieldsToId );
        int length = strings.length;
        String[] strId = new String[length + 1];
        strId[length] = "_id";
        for (int i = 0; i < strings.length; i++) {
            LookupOperation lookup;
            if (strings[i].startsWith ( "_id" )) {
                String str = strings[i];
                String[] split = str.split ( "," );
                lookup = Aggregation.lookup ( collNames[i], split[0], split[1], split[1] );
            } else {
                lookup = Aggregation.lookup ( collNames[i], strings[i], "_id", strings[i] );
            }
            //连表查询

            lists.add ( lookup );
            lists.add ( Aggregation.unwind ( strings[i], true ) );
            strId[i] = strings[i] + "._id";
        }
        AggregationOperation addFieldsToStr = addFieldsToStr ( strId );
        lists.add ( addFieldsToStr );
        lists.add ( skip );
        lists.add ( limit );
        if (pro != null) {
            lists.addAll ( Arrays.asList ( pro ) );
        }
        Aggregation aggregation = Aggregation.newAggregation ( lists );
        return aggregation;
    }

    /**
     * 没有返回值
     */
    public static Aggregation lookup(Criteria criteria, Integer page, Integer pageSize,
                                     String[] strings, String[] collNames) {
        return lookup ( criteria, page, pageSize, strings, collNames, null );
    }

    /**
     * 没有条件，返回值
     */
    public static Aggregation lookup(Integer page, Integer pageSize,
                                     String[] strings, String[] collNames) {
        Criteria criteria = new Criteria ();
        return lookup ( criteria, page, pageSize, strings, collNames, null );
    }

    /**
     * 合并字段成一个数组
     *
     * @param file 字段
     * @param as   数组别名
     * @return Aggregation
     */
    public static Aggregation mergeToArray(AggregationOperation match, String file, String as) {
        AggregationOperation group = var -> new Document ( "$group", new Document ( "_id", null )
                .append ( as, new Document ( "$push", "$" + file ) ) );
        AggregationOperation project = var -> new Document ( "$project", new Document ( as, 1 )
                .append ( "count", new Document ( "$size", "$" + as ) ) );
        AggregationOperation addFieldsToStr = addFieldsToStr ( "_id" );
        return Aggregation.newAggregation ( match, addFieldsToStr, group, project );
    }

    /**
     * 合并字段成一个数组
     * @param map skip limit group(分组字段) keys（查询出的的别名） cz （操作字段 push addToSet） file (要合并的字段)
     * @return Aggregation
     */
    public static List<AggregationOperation> mergeToArray(Map<String, Object> map) {
        return JsonUtil.aggregation ( "Comm.json", "mergeToArray", map );
    }
}
